package bandidong.dao.impl;

import bandidong.dao.MobileDAO;
import bandidong.model.Category;
import bandidong.model.Company;
import bandidong.model.Mobile;
import bandidong.transfermodel.SearchMobileTransferModel;
import bandidong.utils.Constant;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

public class MobileDAOImpl implements MobileDAO {
    
    private EntityManager em;
    
    public MobileDAOImpl(EntityManager em) {
        this.em = em;
    }
    
    @Override
    public List<Mobile> getAllMobiles() {
        try {
            String jpaql = "SELECT m FROM Mobile m";
            Query query = em.createQuery(jpaql);
            List<Mobile> mobiles = (List<Mobile>) query.getResultList();
            return mobiles;
        }
        catch (Exception ex) {
            return null;
        }
    }

    @Override
    public Mobile getMobileById(int id) {
        try {
            String jpaql = "SELECT m FROM Mobile m WHERE m.mobileId = :mobileId";
            Query query = em.createQuery(jpaql);
            query.setParameter("mobileId", id);
            List<Mobile> mobiles = (List<Mobile>) query.getResultList();
            if (mobiles != null && !mobiles.isEmpty()) {
                return mobiles.get(0);
            }
            return null;
        }
        catch (Exception ex) {
            return null;
        }
    }

    @Override
    public String addMobile(Mobile mobile) {
        try {
            em.persist(mobile);
            return Constant.SUCCESS;
        }
        catch (Exception ex) {
            return Constant.ERROR;
        }
    }

    @Override
    public String updateMobile(Mobile mobile) {
        try {
            Mobile m = em.find(Mobile.class, mobile.getMobileId());
            m.setAmount(mobile.getAmount());
            m.setCategory(mobile.getCategory());
            m.setCompany(mobile.getCompany());
            m.setMobileDescription(mobile.getMobileDescription());
            m.setMobileImage(mobile.getMobileImage());
            m.setMobileName(mobile.getMobileName());
            m.setMobilePrice(mobile.getMobilePrice());
            m.setReleaseDate(mobile.getReleaseDate());
            em.merge(m);
            return Constant.SUCCESS;
        }
        catch (Exception ex) {
            return Constant.ERROR;
        }
    }

    @Override
    public String deleteMobile(Mobile mobile) {
        try {
            Mobile m = em.find(Mobile.class, mobile.getMobileId());
            em.remove(m);
            return Constant.SUCCESS;
        }
        catch (Exception ex) {
            return Constant.ERROR;
        }
    }

    @Override
    public List<Mobile> getMobilesCriteria(SearchMobileTransferModel model, int page, int pageSize) {
        Query query = getMobilesWithoutPagging(model);
        if (page <= 0 || pageSize <= 0) {
            return null;
        }
        return query == null ? null : query
                .setFirstResult((page - 1) * pageSize)
                .setMaxResults(pageSize).getResultList();
    }
    
    private Query getMobilesWithoutPagging(SearchMobileTransferModel model) {
        try {
            CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
            CriteriaQuery<Mobile> criteriaQuery = criteriaBuilder.createQuery(Mobile.class);
            Root<Mobile> root = criteriaQuery.from(Mobile.class);
            
            List<Predicate> predicates = new ArrayList<Predicate>();
            
            if (model.getMobileName() != null && !"".equals(model.getMobileName())) {
                Expression<String> mobileName = root.get("mobileName");
                predicates.add(criteriaBuilder.like(mobileName, "%" + model.getMobileName() + "%"));
            }
            if (model.getFromPrice() != null && !"".equals(model.getFromPrice())) {
                double fromPrice = Double.parseDouble(model.getFromPrice());
                Expression<Integer> fPrice = root.get("mobilePrice");
                predicates.add(criteriaBuilder.ge(fPrice, fromPrice));
            }
            if (model.getToPrice() != null && !"".equals(model.getToPrice())) {
                double toPrice = Double.parseDouble(model.getToPrice());
                Expression<Integer> tPrice = root.get("mobilePrice");
                predicates.add(criteriaBuilder.le(tPrice, toPrice));
            }
            if (model.getBeforeReleaseDate() != null) {
                ParameterExpression<Date> dateParam = criteriaBuilder.parameter(Date.class, "rDate");
                Expression<Date> releaseDate = root.<Date>get("releaseDate");
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(releaseDate, dateParam));
            }
            if (!"NONE".equals(model.getCompanyId())) {
                int companyId;
                try {
                    companyId = Integer.parseInt(model.getCompanyId());
                    Join<Mobile, Company> company = root.join("company");
                    predicates.add(criteriaBuilder.equal(company.get("companyId"), companyId));
                }
                catch (Exception ex) {
                    
                }
            }
            if (!"NONE".equals(model.getCategoryId())) {
                int categoryId;
                try {
                    categoryId = Integer.parseInt(model.getCategoryId());
                    Join<Mobile, Category> category = root.join("category");
                    predicates.add(criteriaBuilder.equal(category.get("categoryId"), categoryId));
                }
                catch (Exception ex) {
                    
                }
            }
            
            criteriaQuery.select(root).where(predicates.toArray(new Predicate[predicates.size()]));
            
            TypedQuery<Mobile> query = em.createQuery(criteriaQuery);
            if (model.getBeforeReleaseDate() != null) {
                query.setParameter("rDate", model.getBeforeReleaseDate());
            }
            return query;
        }
        catch (Exception ex) {
            return null;
        }
    }
    
    @Override
    public List<Mobile> getMobilesCriteria(SearchMobileTransferModel model) {
        Query query = getMobilesWithoutPagging(model);
        return query == null ? null : query.getResultList();
    }

    @Override
    public boolean checkExists(String mobileName) {
        try {
            String jpaql = "SELECT m FROM Mobile m WHERE m.mobileName = :mobileName";
            Query query = em.createQuery(jpaql);
            query.setParameter("mobileName", mobileName);
            List<Mobile> mobiles = (List<Mobile>) query.getResultList();
            if (mobiles.isEmpty()) {
                return false;
            }
            return true;
        }
        catch (Exception ex) {
            return true;
        }
    }

    @Override
    public boolean checkExists(String mobileName, int mobileId) {
        try {
            String jpaql = "SELECT m FROM Mobile m WHERE m.mobileName = :mobileName AND m.mobileId != :mobileId";
            Query query = em.createQuery(jpaql);
            query.setParameter("mobileName", mobileName);
            query.setParameter("mobileId", mobileId);
            List<Mobile> mobiles = (List<Mobile>) query.getResultList();
            if (!mobiles.isEmpty()) {
                return true;
            }
            return false;
        }
        catch (Exception ex) {
            return true;
        }
    }

    @Override
    public List<Mobile> getHotMobile(int maxSize) {
        try {
            String jpaql = "SELECT m FROM Mobile m ORDER BY m.releaseDate DESC";
            Query query = em.createQuery(jpaql);
            query.setFirstResult(0);
            query.setMaxResults(maxSize);
            List<Mobile> mobiles = (List<Mobile>) query.getResultList();
            return mobiles;
        }
        catch (Exception ex) {
            return null;
        }
    }

    @Override
    public List<Mobile> getHotMobile(int page, int pageSize) {
        try {
            String jpaql = "SELECT m FROM Mobile m ORDER BY m.releaseDate DESC";
            Query query = em.createQuery(jpaql);
            query.setFirstResult((page - 1) * pageSize);
            query.setMaxResults(pageSize);
            List<Mobile> mobiles = (List<Mobile>) query.getResultList();
            return mobiles;
        }
        catch (Exception ex) {
            return null;
        }
    }

    @Override
    public List<Mobile> getPopularMobile(int maxSize, Date orderDate) {
        try {
            String jpaql = "SELECT m, SUM(o.amount) s FROM Mobile m INNER JOIN m.orderDetailsSet o INNER JOIN o.orders od WHERE od.orderDate >= :orderDate GROUP BY m.mobileId ORDER BY s DESC";
            Query query = em.createQuery(jpaql);
            query.setParameter("orderDate", orderDate);
            query.setFirstResult(0);
            query.setMaxResults(maxSize);
            List<Object[]> objs = query.getResultList();
            List<Mobile> mobiles = new ArrayList<Mobile>();
            for (Object[] obj : objs) {
                mobiles.add((Mobile)obj[0]);
            }
            return mobiles;
        }
        catch (Exception ex) {
            return null;
        }
    }

    @Override
    public List<Mobile> getPopularMobile(int page, int pageSize, Date orderDate) {
        try {
            String jpaql = "SELECT m, SUM(o.amount) s FROM Mobile m INNER JOIN m.orderDetailsSet o INNER JOIN o.orders od WHERE od.orderDate >= :orderDate GROUP BY m.mobileId ORDER BY s DESC";
            Query query = em.createQuery(jpaql);
            query.setParameter("orderDate", orderDate);
            query.setFirstResult((page - 1) * pageSize);
            query.setMaxResults(pageSize);
            List<Object[]> objs = query.getResultList();
            List<Mobile> mobiles = new ArrayList<Mobile>();
            for (Object[] obj : objs) {
                mobiles.add((Mobile)obj[0]);
            }
            return mobiles;
        }
        catch (Exception ex) {
            return null;
        }
    }
}
